package com.spider.spider;

import com.spider.util.ChromeUtil;
import com.spider.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 大麦抢票
 * 驱动链接如下，根据chrome版本下载相应的版本
 * @See http://npm.taobao.org/mirrors/chromedriver/
 */
public class DaMaiConcert {

    private static final String HOME_PAGE = "https://www.damai.cn/";

//    private static final String TARGET_PAGE = "https://detail.damai.cn/item.htm?id=600436975190";
//    private static final String TARGET_PAGE = "https://detail.damai.cn/item.htm?spm=a2oeg.home.card_0.ditem_2.591b23e1CgqDUB&id=601769826415";//测试
    private static final String TARGET_PAGE = "https://detail.damai.cn/item.htm?id=593131142099";//周杰伦

    private static final String PRE_SELECTION_DATE = "周六,周五";//日期,格式: ','隔开

    private static final String PRE_SELECTION_PRICE = "980,1680,1980,2580";//票价,抢票顺序:第一位如果比最后一位小,则默认升序,否则降序 ,格式; ','隔开

    private static final String PRE_SELECTION_QUANTITY = "1";//数量


    public static void main(String[] args) throws InterruptedException {
        System.setProperty("webdriver.chrome.driver", "E:\\webDriver\\chromedriver_win32\\chromedriver.exe");//chromedriver服务地址

        ChromeOptions chromeOptions = new ChromeOptions();

        WebDriver driver = new ChromeDriver(chromeOptions);

        driver.manage().window().maximize();

        /**
         * 3.设置全局隐式等待时间；
         * <br/>使用implicitlyWait方法,设定查找元素的等待时间；
         * <br/>当调用findElement方法的时候，没有立刻找到元素，就会按照设定的隐式等待时长等待下去；
         * <br/>如果超过了设定的等待时间，还没有找到元素，就抛出NoSuchElementException异常；
         */
//        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //设定隐式等待时间为10秒；

        driver.get(HOME_PAGE);

        ChromeUtil.await(2000, driver);

        if (!isLogin(driver)) {

            login(driver);

        }

        driver.get(TARGET_PAGE);
//
//        String abc = "https://buy.damai.cn/orderConfirm?exParams=%7B%22damai%22%3A%221%22%2C%22channel%22%3A%22damai_app%22%2C%22umpChannel%22%3A%2210002%22%2C%22atomSplit%22%3A%221%22%2C%22serviceVersion%22%3A%221.8.5%22%7D&buyParam=602076213690_1_4212704360631&buyNow=true&spm=a2oeg.project.projectinfo.dbuy";
//
//        while (true) {
//
//            try {
//                if (!handleOrderConfirm(abc, driver)) {
//                }
//            } catch (Exception e) {
//                Thread.sleep(100);
//                driver.navigate().refresh();
//            }
//        }



//        //售票时间
        String sellTimeStr = getSellTimeStr(driver);
//        String sellTimeStr = "开售时间：09月08日 13:15";

        //计算售票时间
        LocalDateTime sellTime = ChromeUtil.computeSellTime(sellTimeStr);

        System.out.println("==================>当前时间 = +" + LocalDateTime.now().toString() + ", 售票时间 = " + sellTime.toString());

        ScheduledThreadPoolExecutor scheduled = new ScheduledThreadPoolExecutor(1);
        scheduled.schedule(() -> {

            System.out.println("============>开始抢票!!!!,当前时间 = " + LocalDateTime.now().toString());

            driver.navigate().refresh();

            try {
                execute(driver);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(LocalDateTime.now().toString());
        }, Duration.between(LocalDateTime.now(), sellTime).toMillis() ,  TimeUnit.MILLISECONDS);//计算售票时间与当前时间的时间差,单位是毫秒


//        Thread.sleep(100000);
//        driver.quit();
    }

    /**
     *
     * 获取销售时间
     * @param driver
     * @return
     */
    private static String getSellTimeStr(WebDriver driver) {
        return driver.findElement(By.xpath("//p[@class='Sell__time']")).getText();
    }

    /**
     * 是否登录了
     * @param driver
     * @return
     */
    private static boolean isLogin(WebDriver driver) {
        try {
            WebElement webElement = driver.findElement(By.cssSelector("span[data-spm=dlogin]"));
            webElement.getText();
            return false;
        } catch (Exception e) {
            return true;
        }
    }

    private static void login(WebDriver driver) throws InterruptedException {

        String mainWindowHandle = driver.getWindowHandle();

        try {
            WebElement webElement = driver.findElement(By.cssSelector("a[class=J_userinfo_name][data-spm=duserinfo]"));//多属性
            System.out.println(webElement.getAttribute("href"));

            driver.get(webElement.getAttribute("href"));

            System.out.println("curUrl = " + driver.getCurrentUrl());


        } catch (Exception e) {
            System.out.println(e);

            System.out.println("找不到登录!!!!!!");
        }

        driver.switchTo().frame("alibaba-login-box");

        driver.findElement(By.cssSelector("a[attr-type=qq]")).click();

        System.out.println(driver.getCurrentUrl());

        Set<String> windowHandles = driver.getWindowHandles();

        for (String windowHandle : windowHandles) {
            if (!mainWindowHandle.equals(windowHandle)) {
                driver.switchTo().window(windowHandle);

                ChromeUtil.await(200, driver);

                System.out.println(driver.getCurrentUrl());

                driver.switchTo().frame("ptlogin_iframe");

                ChromeUtil.await(200, driver);

                driver.findElement(By.cssSelector("a[hidefocus=true][draggable=false]")).click();

                ChromeUtil.await(200, driver);

                driver.switchTo().window(mainWindowHandle);

                //时间一定要久点
                ChromeUtil.await(20000, driver);

                WebElement homePage = driver.findElement(By.cssSelector("a[class=type-recommend][data-spm=dhome]"));

                System.out.println(homePage.getAttribute("href"));

                driver.get(homePage.getAttribute("href"));

                System.out.println(driver.getCurrentUrl());
            }
        }

    }


    public static void execute(WebDriver driver) throws InterruptedException {

        //场次xpath
        List<WebElement> performsElement = driver.findElements(By.xpath("//div[@class='perform__order__select perform__order__select__performs']/*/div[@class='select_right_list']/div[contains(@class,'select_right_list_item')]"));

        List<String> preSelectionDate = Arrays.asList(PRE_SELECTION_DATE.split(","));

        List<String> preSelectionPriceList = Arrays.asList(PRE_SELECTION_PRICE.split(","));

        List<WebElement> dateList = new ArrayList<>();

        for (WebElement webElement : performsElement) {

            WebElement dateElement = webElement.findElement(By.xpath("./span[2]"));

            System.out.println(">>>>>>>>>>>>>>>>>>>时间 = " + dateElement.getText());

            preSelectionDate.forEach(p->{

                if (dateElement.getText().contains(p)) {
                    dateList.add(webElement);
                }
            });
        }

        System.out.println("匹配上的日期size = " + dateList.size());

        boolean needRefresh = false;
        if (dateList.size() == 1) {
            needRefresh = true;
        }

        while (true){

            Map<WebElement, Set<Integer>> cache = new HashMap<>();
            for (WebElement webElement : dateList) {

                if (needRefresh) {
                    System.out.println("===============>>开始刷新!!!!!!");
                    driver.navigate().refresh();//刷新
                }else {
                    webElement.click();
                }

                //票价
                List<WebElement> ticketPriceElementList = driver.findElements(By.xpath("//div[@class='perform__order__select']/*/div[@class='select_right_list']/div[contains(@class,'select_right_list_item')]"));

                //设置抢票的顺序, 当票价的 第一位大于最后一位 则降序 ,否则默认升序
                setTicketPriceSort(ticketPriceElementList);

                for (int i = 0; i < ticketPriceElementList.size(); i++) {
                    WebElement ticketPriceElement = ticketPriceElementList.get(i);

                    //获取单价
                    String price = ticketPriceElement.findElement(By.xpath("./div[@class='skuname']")).getText();

                    boolean check = false;
                    for (String preSelectionPrice : preSelectionPriceList) {
                        if (price.contains(preSelectionPrice)) {
                            check = true;
                            break;
                        }
                    }

                    if (!check) {
                        continue;
                    }

                    //是否有足够的票可以抢
                    if (!hasEnoughTicket(ticketPriceElement)) {
                        continue;
                    }

                    System.out.println("======================>当前票价 = " + price);

                    ticketPriceElement.click();

//                    Set<Integer> indexSet = cache.get(webElement);
//                    if (org.springframework.util.CollectionUtils.isEmpty(indexSet)) {
//                        indexSet = new HashSet<>();
//                    }
//                    indexSet.add(i);

                    if (!hasQuantity(driver)) {

                        System.out.println("===================>即将开售!!!!!!!,当前票价 = " + price);
                        continue;
                    }

                    //计算数量
//                    computeQuantity(driver);

                    //计算合计
                    computeTotolPrice(driver);

                    //进入订单页面
                    goOrderPage(driver);

                    if (handleOrderConfirm(driver)) {
                        //停止遍历
                        return;
                    }
                }

                Thread.sleep(100);

            }

        }

    }
    private static boolean handleOrderConfirm( WebDriver driver) {
        return handleOrderConfirm(null, driver);
    }

    /**
     * 处理订单页面
     */
    private static boolean handleOrderConfirm(String targetPath, WebDriver driver) {
        if (StringUtils.isNotBlank(targetPath)) {
            driver.get(targetPath);
        }

//        driver.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);

//        if (!hasDeliveryMethod(driver)) {
//            System.out.println("=>>>>>>>>>>抢不到票!!!!!");
//            driver.navigate().refresh();
//            return false;
//        }

        List<WebElement> buyers = driver.findElements(By.xpath("//div[@class='next-row next-row-no-padding buyer-list']/*"));
        for (WebElement buyer : buyers) {
            //TODO 这里根据人数选择人
            buyer.click();
        }

        WebElement submitElement = driver.findElement(By.xpath("//div[@class='submit-wrapper']/button[@class='next-btn next-btn-normal next-btn-medium'][@type='button']"));
        submitElement.click();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return true;
    }

    private static boolean hasDeliveryMethod(WebDriver driver) {
        WebDriverWait wait = new WebDriverWait(driver, 1);
        try {

            wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@class='next-row next-row-no-padding delivery-title']")));
//            wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("header")));
//            /**
//             * 自定义显示等待
//             */
//            WebElement deliveryMethodElement =
//            (new WebDriverWait(driver, 1)).until(new ExpectedCondition<WebElement>() {
//                @Override
//                public WebElement apply(WebDriver driver){
//                    return driver.findElement();
//                }
//            });
            return true;
        }catch (Exception e){
            System.out.println("当前时间 = " + LocalDateTime.now().toString());
            return false;
        }
    }

    /**
     * 进入订单页面
     * @param driver
     */
    private static void goOrderPage(WebDriver driver) {
        WebElement dbuys = driver.findElement(By.xpath("//div[@class='buybtn'][@data-spm='dbuy']"));
        dbuys.click();

        System.out.println("=================>订单页面url = " + driver.getCurrentUrl());
        Set<String> windowHandles = driver.getWindowHandles();

        System.out.println("=================>窗口的size = " + windowHandles.size());

    }

    private static boolean hasQuantity(WebDriver driver) {
        WebDriverWait wait = new WebDriverWait(driver, 1);

        try {
            System.out.println("================>检查数量,当前时间 = " + LocalDateTime.now().toString());

            wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@class='number_right_info']/*/a[2]")));
//            WebElement plusElement = driver.findElement(By.xpath("//div[@class='number_right_info']/*/a[2]"));
            return true;
        } catch (Exception e) {
            System.out.println("================>检查数量失败,当前时间 = " + LocalDateTime.now().toString());
            return false;
        }
    }

    private static void computeQuantity(WebDriver driver) {
        WebElement plusElement = driver.findElement(By.xpath("//div[@class='number_right_info']/*/a[2]"));
        plusElement.click();
    }

    /**
     * 是否有足够的票可以抢
     *
     * @return
     */
    private static boolean hasEnoughTicket(WebElement ticketPriceElement) {
        List<WebElement> result = ticketPriceElement.findElements(By.xpath("./*"));
        return result.size() == 1 ? true : false;
    }

    /**
     * 设置抢票的顺序
     *
     * @param ticketPriceElement
     */
    private static void setTicketPriceSort(List<WebElement> ticketPriceElement) {
        List<String> preSelectionPriceList = Arrays.asList(PRE_SELECTION_PRICE.split(","));

        boolean sortAsc = true;//升序

        if (Integer.valueOf(preSelectionPriceList.get(0)) > Integer.valueOf(preSelectionPriceList.get(preSelectionPriceList.size() - 1))) {
            //当票价的 第一位大于最后一位 则降序 ,否则默认升序
            sortAsc = false;
        }

        if (!sortAsc) {
            Collections.reverse(ticketPriceElement);
        }
    }

    /**
     * 计算合计金额
     *
     * @param driver
     */
    private static void computeTotolPrice(WebDriver driver) {
        WebElement totolPrice = driver.findElement(By.xpath("//span[@class='totol__price']"));

        System.out.println(">>>>>>>>>>>>>>>>>>>>>>合计价格 = " + totolPrice.getText());
    }

}
